package top.wilsonlv.jaguar.cloud.auth.extension.face;

import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.springframework.security.authentication.AccountStatusException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.util.StringUtils;
import top.wilsonlv.jaguar.cloud.auth.sdk.enums.PrincipalType;
import top.wilsonlv.jaguar.cloud.auth.sdk.token.FaceAuthenticationToken;
import top.wilsonlv.jaguar.commons.web.util.WebUtil;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;

import static top.wilsonlv.jaguar.cloud.auth.extension.OAuth2ExtensionContant.*;

/**
 * @author lvws
 * @since 2022/3/30 0030
 */
public class FaceTokenGranter extends AbstractTokenGranter {

    private static final String GRANT_TYPE = "face";

    private final AuthenticationManager authenticationManager;

    public FaceTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices,
                            ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        this.authenticationManager = authenticationManager;
    }

    @SneakyThrows
    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        HttpServletRequest request = WebUtil.getRequest();
        assert request != null;

        String username = request.getParameter(QUERY_PARAMETER_USERNAME_KEY);
        String deviceUid = request.getParameter(QUERY_PARAMETER_DEVICE_UID_KEY);

        if (!StringUtils.hasText(username) && !StringUtils.hasText(deviceUid)) {
            throw new InvalidGrantException("设备ID与用户名不可同时为空");
        }

        String face;
        try (ServletInputStream inputStream = request.getInputStream();
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            IOUtils.copy(inputStream, outputStream);
            face = outputStream.toString();
        }

        if (!StringUtils.hasText(face)) {
            throw new InvalidGrantException("人脸信息为非空");
        }

        if (face.startsWith(DATA_IMAGE_PNG_BASE64)) {
            face = face.substring(DATA_IMAGE_PNG_BASE64.length());
        }

        FaceAuthenticationToken token;
        if (StringUtils.hasText(username)) {
            token = new FaceAuthenticationToken(username, face, PrincipalType.USERNAME);
        } else {
            token = new FaceAuthenticationToken(deviceUid, face, PrincipalType.DEVICE_ID);
        }

        Authentication authentication;
        try {
            authentication = authenticationManager.authenticate(token);
        } catch (AccountStatusException ase) {
            throw new InvalidGrantException(ase.getMessage());
        }

        OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
        return new OAuth2Authentication(storedOAuth2Request, authentication);
    }
}
